--- title: "01-JVM(Java Virtual Machine)" created: 2025-12-02 tags: - Java --- # JVM(Java Virtual Machine) ## 知识点 ### 1. **JVM 内存结构**: JVM 的内存结构大致分为以下几个区域: - **方法区**(Method Area):用于存储类信息、常量、静态变量和即时编译器编译后的代码。JVM 规范要求方法区是一个共享内存区域,各个线程都可以访问。 - **堆区**(Heap):用于存储所有的对象实例(类实例)。堆是垃圾回收(GC)的主要区域,GC 会对堆中的对象进行内存回收。 - **栈区**(Stack):每个线程都会有一个独立的栈,用于存储局部变量、方法调用、返回地址等信息。每当方法被调用时,栈会分配一个栈帧,栈帧中存储方法的局部变量、操作数栈等。 - **程序计数器**(Program Counter Register):指向当前线程执行的字节码指令的地址。每个线程都有独立的程序计数器。 - **本地方法栈**(Native Method Stack):为 JNI(Java Native Interface)调用提供服务,存储 Java 调用本地方法时的参数和返回值。 ### 2. **JVM 生命周期**: JVM 生命周期大致包括以下几个阶段: - **启动阶段**:启动 JVM 时,加载 Java 类,初始化 JVM 环境。 - **加载阶段**:JVM 启动后,首先加载用户指定的主类。 - **执行阶段**:JVM 执行主类中的 `main` 方法,并开始解释执行字节码,或者在有 JIT 编译器时进行编译。 - **结束阶段**:当 `main` 方法执行完毕或 JVM 发生异常终止时,JVM 结束运行,释放资源。 ### 3. **主流虚拟机**: 主流的 JVM 实现包括: - **HotSpot JVM**:Oracle 提供的官方 JVM,实现了大部分 JVM 规范,支持 JIT 编译。 - **OpenJ9 JVM**:由 IBM 开发的 JVM,支持开源和商用,性能优化针对特定场景(如云计算环境)。 - **GraalVM**:是一个多语言虚拟机,可以执行 Java、JavaScript、Ruby 等多种语言的代码,支持高效的 JIT 编译和 AOT 编译。 - **Zulu/OpenJDK**:是 Oracle JDK 的开源实现,主要用于在 Linux、Windows 和 macOS 上运行 Java 应用。 ### 4. **Java 代码执行流程**: - **编译阶段**:Java 源代码(.java 文件)通过 `javac` 编译器编译成字节码(.class 文件)。 - **类加载**:字节码通过类加载器加载到内存中。 - **字节码解释**:JVM 的解释器将字节码转换为平台相关的机器码进行执行。 - **JIT 编译**:JVM 通过 JIT 编译将热点代码(经常执行的代码)编译为本地机器码,优化执行效率。 ### 5. **类加载与类加载器**: - **类加载器**是 JVM 中用来加载类的组件。它负责将字节码文件加载到 JVM 中,并将它们转化为类对象,供后续使用。 - **类加载过程**:类加载过程包括以下几个步骤: 1. **加载**:通过类加载器将类的字节码加载到内存。 2. **验证**:验证加载的字节码是否符合 JVM 的规范。 3. **准备**:为类的静态变量分配内存,并设定初始值。 4. **解析**:解析类中的符号引用,转化为直接引用。 5. **初始化**:执行类的初始化代码(如静态代码块)。 - **双亲委派机制**:JVM 中的类加载器采用双亲委派模型,即当一个类加载器收到加载请求时,它会先委托给父类加载器去加载,只有在父类加载器无法加载时,子类加载器才会自己加载。这样可以避免重复加载和类冲突。 ### 6. **垃圾回收与垃圾回收策略**: - **垃圾回收器**:负责回收 JVM 堆中不再使用的对象,释放内存。常见的垃圾回收器有: - **Serial GC**:单线程垃圾回收器,适用于单核处理器。 - **Parallel GC**:多线程垃圾回收器,适用于多核处理器。 - **G1 GC**:用于低延迟和大堆内存的场景,适合大规模的应用。 - **垃圾回收策略**:JVM 使用不同的垃圾回收策略,通常根据堆的大小、对象的生命周期以及应用的要求来选择。 - **垃圾回收算法**: - **标记-清除算法**:标记所有需要回收的对象,然后清除这些对象。 - **复制算法**:将堆分为两个区域,每次回收时将存活的对象复制到另一区域。 - **标记-压缩算法**:标记需要回收的对象并进行压缩,避免产生内存碎片。 - **分代回收**:根据对象的存活时间,将对象分为不同的代,分别进行回收。 - **Stop-the-World**:是指垃圾回收过程中,所有应用线程被暂停,直到垃圾回收完成。 ### 7. **字节码**: 字节码是 Java 源代码编译后的中间代码,它是与平台无关的。JVM 通过解释执行或 JIT 编译将字节码转化为机器码,进而执行。 ### 8. **内存分配与回收**: - **堆内存分配**:JVM 会将内存分配给对象实例,堆是内存分配的主要区域。 - **栈内存分配**:每个线程都会有一个栈,用于存储方法调用和局部变量。栈内存一般是线程私有的。 ### 9. **JVM 性能调优**: - **性能分析方法**:通过监控 JVM 的运行状况(如 GC 日志、内存使用情况)来分析性能瓶颈。 - **常用工具**: - **jconsole**:用于监控和管理 JVM。 - **VisualVM**:可视化的 JVM 监控工具,适合性能调优。 - **GC Logs**:查看垃圾回收的日志,分析垃圾回收的效率和停顿时间。 - **参数设置**:通过 JVM 启动参数来调节堆大小、GC 策略等参数,优化性能。例如,`-Xmx` 设置最大堆大小,`-XX:+UseG1GC` 启用 G1 垃圾回收器。 - **Java 探针**:用于在生产环境中动态监控 JVM 的健康状态。 - **线上故障分析**:在生产环境中,通过 JVM 日志和性能数据分析故障,找出性能瓶颈或异常问题。 ## 问题 ### 1. **JVM 内存模型(JMM)**: JVM 内存模型(Java Memory Model,简称 JMM)是 Java 并发编程的核心概念之一,它定义了不同线程之间如何共享内存,并且规定了内存操作的顺序,以保证多线程并发程序的正确性。JMM 主要涉及以下几个方面: #### **JMM 的目标** JMM 的目标是提供一个统一的规则,确保多线程环境下,线程之间的数据交换和同步不会引发竞态条件、内存可见性问题和指令重排问题。通过合理的内存模型,Java 能够保证并发程序的可靠性和一致性。 #### **JMM 的主要概念** 1. **主内存(Main Memory)和工作内存(Working Memory)**: - **主内存**:每个线程的共享内存区域,存储着所有变量的值。所有的实例字段、静态字段和数组元素都存储在主内存中。 - **工作内存**:每个线程有自己的工作内存,工作内存中存放的是从主内存中拷贝过来的变量的副本。线程对共享变量的操作通常是在工作内存中进行的,然后再同步回主内存。 2. **内存可见性(Visibility)**: - 线程的工作内存中的变量修改对其他线程是否可见是一个重要问题。在 JMM 中,变量的修改是否能被其他线程看到,取决于同步操作。比如,在没有适当同步的情况下,一个线程对变量的修改可能永远不会被其他线程看到。 - **同步关键字(synchronized)**、**volatile 关键字**以及 **锁** 等都可以确保内存可见性。 3. **有序性(Ordering)**: - 由于编译器、处理器等优化技术,程序中操作的执行顺序可能会与代码中的顺序不同,这被称为**指令重排**。JMM 通过保证一定的规则来控制指令的执行顺序,以保证程序的正确性。 - **happens-before 规则**:JMM 定义了线程间的执行顺序,通过一些同步机制来保证某些操作先于其他操作执行。比如,`synchronized` 和 `volatile` 就提供了 happens-before 保证,确保某些操作的先后顺序。 4. **原子性(Atomicity)**: - JMM 还保证了对某些操作的原子性。在 JMM 中,简单的读写操作是原子的,但是像复合操作(例如:`i++`)这样的操作不是原子性的,可能会导致并发问题。 #### **JMM 中的同步机制** 为了保证线程间的内存可见性和操作顺序,Java 提供了几种同步机制: 1. **synchronized**:Java 的 `synchronized` 关键字可以用于方法或代码块,确保同一时刻只有一个线程能执行被同步修饰的代码块,并且同步块中的变量对其他线程是可见的。 2. **volatile**:`volatile` 关键字确保每次访问变量时都直接从主内存中读取,而不是从线程的工作内存中读取。它提供了轻量级的同步机制,但只保证单个变量的可见性,而不提供原子性或顺序性保证。 3. **锁(Lock)**:Java 通过显式锁(如 `ReentrantLock`)来提供更多的控制,保证同一时刻只有一个线程能访问某些共享资源。 #### **JMM 的关键问题** 1. **内存可见性问题**: 线程之间的变量修改在不同的工作内存中不会立刻同步到主内存,可能导致其他线程看不到最新的变量值。这是 JMM 需要解决的一个关键问题。 2. **指令重排问题**: 为了提高程序执行的效率,编译器和 CPU 可能会将代码中的指令顺序重排,导致多线程程序的执行顺序与程序源代码中的顺序不一致,进而可能出现逻辑错误。JMM 使用 happens-before 规则来保证线程操作的有序性,避免指令重排带来的问题。 3. **原子性问题**: 多线程环境中对共享资源的操作可能出现竞态条件,导致操作不是原子的。为了保证操作的原子性,Java 提供了同步机制。 #### **JMM 的重要性** 理解 JMM 对于编写并发程序至关重要。它帮助开发者理解多线程环境中线程之间是如何共享数据的,以及如何通过同步机制保证程序的正确性。掌握 JMM 能够有效避免线程安全问题和并发 bug。 #### 结论: JVM 内存模型是 Java 并发编程的基础,它通过对线程间内存共享、操作顺序、内存可见性、指令重排等问题进行详细定义和控制,确保多线程程序的正确性。通过 `synchronized`、`volatile`、锁等机制,Java 提供了丰富的工具,帮助开发者在复杂的并发环境中编写高效、可靠的代码。 ### **2.JVM 内存为什么要分代**: JVM 堆内存被分为 **年轻代**、**老年代** 和 **永久代**(或元空间),这是为了优化垃圾回收。年轻代主要用于存放新生对象,老年代存放存活时间较长的对象,垃圾回收可以针对年轻代和老年代进行不同的策略,以提高回收效率。 JVM 的堆内存分代(**Generation**)是为了优化垃圾回收(GC)过程,提升内存管理的效率。在传统的 Java 程序中,程序的对象生命周期有很大的差异,一些对象可能仅存在短暂的时间,而另一些对象则会长时间存活。因此,将堆内存划分为多个区域,可以使垃圾回收器更加高效地处理这些不同生命周期的对象。 JVM 将堆内存分为以下几个主要区域: 1. **年轻代(Young Generation)**: - 年轻代是存储新生对象的区域。Java 程序通常会创建大量短暂存活的对象,这些对象的生命周期很短,适合放在年轻代中。年轻代的回收通常很频繁,因为大部分对象在创建后不久就会被垃圾回收。 - 年轻代本身又可以分为三个部分:**Eden 空间**(新对象的创建区域)、**Survivor 0** 和 **Survivor 1**(存放经过一次或多次 GC 仍然存活的对象)。 2. **老年代(Old Generation)**: - 老年代存储那些存活时间较长的对象。一般来说,年轻代中的对象如果经过多次垃圾回收仍然存活,就会被晋升到老年代。老年代的垃圾回收相对较少,因为其中的对象一般较为稳定。 - 老年代的回收成本较高,因此会使用不同的垃圾回收策略(如 Full GC)来进行回收。 3. **元空间(Metaspace)**: - 从 Java 8 开始,**方法区**被移到了**元空间**,用于存储类的元数据(如类信息、常量池、方法信息等)。元空间位于本地内存中,不再占用堆内存。 - 类的元数据通常是长时间存活的,因此不需要频繁回收。 **为什么要分代?** 1. **优化垃圾回收的效率**: - **对象的生命周期**:在 Java 程序中,大部分对象是短暂存在的,这些对象在创建后很快就会被销毁。垃圾回收器如果每次都检查整个堆内存,会造成大量的性能开销。通过将对象按照生命周期进行分代,可以使垃圾回收器只针对年轻代进行频繁的回收,而将老年代的回收频率降低,从而提高回收效率。 - **年轻代 GC 的频繁性**:年轻代的垃圾回收(**Minor GC**)通常是快速的,因为它只回收生命周期短、较为简单的对象。与此不同,老年代的垃圾回收(**Major GC** 或 **Full GC**)较为复杂且耗时。因此,分代能够使年轻代和老年代的垃圾回收策略和频率有所区别,避免不必要的性能浪费。 2. **减少 GC 停顿时间**: - **年轻代的快速回收**:因为大部分对象的生命周期较短,年轻代中的对象会很快被回收。通过频繁地对年轻代进行垃圾回收,JVM 能够减少长时间停顿的情况,提升程序的响应性和并发性能。 - **老年代的回收优化**:老年代的对象通常需要较长时间才能被回收,因此不需要频繁的垃圾回收。老年代的回收(如 Full GC)虽然耗时较长,但发生频率较低,从而避免频繁的全局回收。 3. **内存分配优化**: - **快速分配空间**:在年轻代中,新的对象会快速地分配内存。这是因为年轻代使用了 **Eden 空间** 和两个 **Survivor 空间** 的设计。每当发生 Minor GC 时,存活的对象会从 Eden 区转移到 Survivor 区,经过多次 GC 后再晋升到老年代。 - **对象晋升和空间回收**:通过代际划分,JVM 可以根据对象的年龄来决定它们应当存储在哪个区域,这样可以避免长期存活的对象占用过多的内存空间,同时通过回收短生命周期的对象来减轻内存压力。 4. **垃圾回收策略的灵活性**: - **针对不同代的不同回收策略**:年轻代和老年代的垃圾回收有不同的策略。例如,年轻代使用复制算法(**Copying**)来实现高效的垃圾回收,而老年代则通常使用标记-清除(**Mark-Sweep**)和标记-压缩(**Mark-Compact**)等算法来减少内存碎片。分代使得 JVM 能够灵活地选择适合每个代的回收算法。 总之,JVM 将堆内存分为年轻代、老年代和元空间是为了提高垃圾回收的效率、减少停顿时间,并根据对象的生命周期选择适当的回收策略。通过这种分代机制,JVM 能够更高效地管理内存,保证多线程并发程序的性能。 ### 3. **介绍一次完整的 GC 流程**: - **标记阶段**:首先标记所有需要回收的对象。 - **清除阶段**:删除被标记的对象,释放内存。 - **整理阶段**:移动对象,避免内存碎片。 - 这个流程在不同的垃圾回收器中可能略有不同,但大体相似。 **一次完整的 GC 流程** 垃圾回收(GC)是 JVM 中用于自动管理内存的机制。JVM 通过垃圾回收器来清理堆内存中的不再使用的对象,从而释放内存。GC 主要集中在堆内存的回收上,尤其是年轻代和老年代的管理。下面是一次完整的垃圾回收(GC)流程的详细介绍: **1. GC 触发的时机** 垃圾回收的触发通常有以下几种情况: - **年轻代空间不足**:当年轻代的 Eden 区空间不足时,JVM 会触发一次 Minor GC(年轻代垃圾回收)。这是最常见的 GC 类型,回收的对象大多是生命周期较短的对象。 - **老年代空间不足**:当老年代空间不足时,JVM 会触发一次 Full GC(完全垃圾回收),这通常是一次较长的回收过程。此时不仅回收年轻代,还会回收老年代和永久代(或元空间)。 - **JVM 手动触发**:通过调用 `System.gc()` 或 `Runtime.getRuntime().gc()` 可以手动触发垃圾回收,但这通常不推荐在生产环境中使用。 **2. GC 类型** 在 JVM 中,垃圾回收主要分为以下几种类型: 1. **Minor GC**(年轻代 GC): - **触发条件**:年轻代的 Eden 区空间不足时会触发 Minor GC。 - **处理区域**:只回收年轻代的对象(Eden 区和 Survivor 区)。 - **执行速度**:由于年轻代的对象通常生命周期较短,回收时大多数对象都会被清除,所以 Minor GC 执行较为高效,暂停时间较短。 2. **Major GC 或 Full GC**(老年代 GC): - **触发条件**:当老年代空间不足时触发 Full GC。 - **处理区域**:不仅回收年轻代,还会回收老年代和永久代(或元空间)。 - **执行速度**:由于老年代中存活的对象较多,回收时需要更长的时间,暂停时间较长。 **3. 完整 GC 流程** **(1)Minor GC 过程(年轻代)** Minor GC 是在年轻代内存空间不足时触发的回收过程,主要涉及以下步骤: - **标记阶段(Mark)**: - 在这个阶段,JVM 会遍历年轻代中的对象,标记所有可达(存活)对象。可达的对象是那些从根对象(如栈中的局部变量、静态字段等)能够直接或间接访问到的对象。 - 标记阶段的目的是为了确定哪些对象是可以回收的。 - **清除阶段(Sweep)**: - 在标记阶段完成后,JVM 会清除掉所有未标记的对象,即那些不可达的对象。这些对象被认为是垃圾,可以从堆中回收。 - **压缩阶段(Compact)**: - 为了避免内存碎片,JVM 会将存活的对象压缩到一起。这样不仅清理了不再使用的对象,还保证了堆内存的连续性,从而提高内存的使用效率。 - **对象晋升**: - 在 Minor GC 结束时,存活的对象会从年轻代的 Survivor 区转移到老年代(如果这些对象已经存活了多次 GC)。这意味着一些“长期存活”的对象会被晋升到老年代。 **(2)Full GC 过程(老年代)** Full GC 是在老年代内存不足时触发的垃圾回收,过程更加复杂,主要包括: - **标记阶段(Mark)**: - 类似于 Minor GC,JVM 会标记出所有存活的对象。标记的对象会被认为是可达的,这些对象不需要被回收。 - **清除阶段(Sweep)**: - 清除所有不可达的对象,将其从内存中回收。对于老年代来说,通常这一步操作会比较慢,因为老年代存活的对象比较多。 - **压缩阶段(Compact)**: - 经过清理的内存区域会被压缩,回收的空间被整合起来,避免碎片问题。此步骤的目的是减少内存碎片,优化老年代的内存分配。 - **类的卸载(如果有永久代/元空间)**: - 如果垃圾回收器发现永久代或元空间中有不再使用的类,它也会卸载这些类,释放相关的内存。 **(3)JVM 对象的晋升** 在垃圾回收过程中,JVM 会根据对象的存活时间和回收情况,将年轻代中存活的对象晋升到老年代。晋升的条件通常是: - 对象在年轻代经过一定次数的 GC 仍然存活。 - 对象的年龄达到了老年代的晋升阈值。 这个机制有助于减少老年代的频繁回收,从而提高 GC 的效率。 **(4)Stop-The-World** 在垃圾回收过程中,JVM 会发生 **Stop-the-World** 事件,意味着所有应用程序的线程都会暂停,直到 GC 完成。具体的暂停时间会根据垃圾回收的种类和堆的大小而有所不同。Minor GC 的暂停时间通常较短,而 Full GC 的暂停时间则较长。 **(5)GC 日志与分析** 在进行垃圾回收时,JVM 会生成 GC 日志,记录每次 GC 的详细信息,包括垃圾回收的类型(Minor/Full)、回收前后的内存情况、回收时间等。通过分析这些日志,开发者可以监控 JVM 的内存使用情况,判断是否需要调整堆大小、垃圾回收策略等。 **4. GC 策略与优化** JVM 提供了多种垃圾回收策略,可以根据不同应用的需求进行调整: - **Serial GC**:单线程垃圾回收,适用于内存小、单核 CPU 环境。 - **Parallel GC**:多线程垃圾回收,适用于多核 CPU 环境,可以提高垃圾回收效率。 - **G1 GC**:适用于大堆内存和低延迟场景,能够将回收过程分成多个小步骤,减少停顿时间。 - **ZGC** 和 **Shenandoah GC**:低延迟垃圾回收器,适用于对响应时间要求极高的应用。 **总结** 一次完整的垃圾回收流程包括标记、清除、压缩等步骤。首先进行 Minor GC 回收年轻代对象,当年轻代空间不足时触发;如果老年代内存不足,则会触发 Full GC,进行全堆的回收。垃圾回收器通过这些过程确保 JVM 堆内存中的对象能够被高效管理,并最大化地利用内存。 ### 4. **介绍双亲委派模型,为什么需要它?** 双亲委派机制是类加载器的一种结构,它确保了类的加载顺序,避免了类加载的冲突和重复加载。通过委派机制,子类加载器优先将加载请求传递给父类加载器,从而保证了核心类库的安全性和一致性。 **双亲委派模型(Parent Delegation Model)** 双亲委派模型是 Java 类加载机制的一种设计模式。该模型规定了类加载器在加载类时的委派关系,即每个类加载器都有一个父类加载器,类加载器在接收到类加载请求时,首先将请求委派给父类加载器处理,只有父类加载器无法处理时,子类加载器才会自己处理。这种模型确保了类加载的一致性和安全性,避免了类的重复加载和冲突。 **双亲委派模型的工作原理** 1. **类加载器的层次结构**: JVM 中有多个类加载器,每个类加载器都有自己的职责。Java 的类加载器层次结构通常包括: - **Bootstrap ClassLoader**:顶级类加载器,负责加载 JDK 中的核心类库(如 `rt.jar` 中的类)。这个加载器通常是由 C++ 编写,直接与 JVM 相关联。 - **Extension ClassLoader**:负责加载 JDK 中扩展库(如 `lib/ext` 目录下的类)。它的父类加载器是 Bootstrap ClassLoader。 - **System ClassLoader**:也称为应用程序类加载器,负责加载应用程序的类路径(通常是 `classpath` 下的类)。它的父类加载器是 Extension ClassLoader。 - **自定义类加载器**:用户可以通过继承 `ClassLoader` 来创建自己的类加载器,用于加载应用程序特定的类。 2. **委派过程**: - 当一个类加载器接收到一个类加载请求时,它首先检查是否已经加载过该类。如果已经加载,它就直接返回。 - 如果该类还没有被加载,类加载器会将加载请求委派给父类加载器。父类加载器会采用同样的方式处理请求。 - 只有当父类加载器无法加载时,子类加载器才会自行加载该类。 - 这种委派机制保证了类的加载顺序和一致性。例如,应用程序的类不能覆盖 JDK 中的核心类,避免了类的冲突。 **为什么需要双亲委派模型?** 1. **保证核心类的安全性和一致性**: 双亲委派模型的最大优势是保证了 Java 核心类(如 `java.lang.*`、`java.util.*` 等)不被用户的自定义类覆盖。由于所有的类加载请求都首先委派给 Bootstrap ClassLoader 处理,因此 JDK 核心库的类始终由顶层加载器加载,防止了应用程序类意外覆盖这些核心类。例如,如果没有双亲委派机制,应用程序就可能会加载一个与 JDK 核心库同名的类,这样就可能导致系统崩溃或错误的行为。 2. **防止类加载的重复和冲突**: 双亲委派模型避免了类的重复加载。通过让父加载器先尝试加载类,确保了类的加载不会被多个加载器重复执行。这样,类加载器可以通过委派关系来保证每个类只加载一次。 3. **提高类加载的规范性和可维护性**: 通过这种模型,类加载器的层次结构更加清晰,易于理解和维护。每个类加载器都有其固定的职责和加载范围,避免了类加载混乱和重复的情况。这种清晰的设计也使得 Java 在多层次、多模块的环境中表现得更加稳定和高效。 4. **支持自定义类加载器**: 双亲委派模型不仅确保了系统核心类的加载安全性,还为开发者提供了灵活的扩展性。开发者可以创建自定义的类加载器,通过实现自己的加载逻辑来加载应用程序特定的类,而不必担心覆盖 Java 核心库类或引发类加载冲突。 **双亲委派模型的实际应用** 1. **应用程序的类加载**: 在实际应用中,应用程序的类通常由系统类加载器(即应用程序类加载器)来加载。但是如果用户的类有冲突或依赖于其他库,系统类加载器会将请求委派给 Extension ClassLoader 或 Bootstrap ClassLoader 进行处理。 2. **自定义类加载器**: 自定义类加载器是通过继承 `ClassLoader` 类实现的。在开发 Java EE 应用或集成某些第三方框架时,经常需要自定义类加载器来加载特定的类。自定义加载器通常会使用双亲委派模型,从而确保核心类不会被覆盖。 3. **动态加载和隔离**: 双亲委派模型可以帮助管理不同版本的类库。通过使用不同的类加载器加载不同版本的类,可以实现类库的隔离和版本管理。例如,某些复杂的 Java Web 容器(如 Tomcat)通过不同的类加载器加载 Web 应用和容器自己的类,以避免版本冲突和类覆盖。 **总结** 双亲委派模型是一种保障 Java 类加载器安全性、规范性和高效性的设计模式。通过将类加载请求委派给父类加载器,Java 保证了核心类不会被应用程序的类覆盖,避免了类的冲突和重复加载问题。这个模型不仅为 Java 系统提供了一个稳定的类加载机制,也支持了用户自定义类加载器,从而提供了灵活的扩展能力。在实际开发中,了解并遵循双亲委派模型,能够帮助开发者高效地管理类加载过程,并确保 Java 应用程序的稳定运行。 --- ⬅️ [[00-java的优势|java的优势]] 🏠 [[00-Java|00-Java]] ➡️ [[02-字节码|字节码]]